/**
 * All rights Reserved, Designed By OprCalf
 * Copyright:    Copyright(C) 2016-2020
 * Company       OprCalf Ltd.
 */

package com.platform.gateway.common.aspect;

import java.lang.reflect.Method;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.google.common.util.concurrent.RateLimiter;
import com.platform.gateway.common.annotation.RateLimit;
import com.platform.gateway.common.utils.MsgUtils;

import lombok.extern.slf4j.Slf4j;

/**@projectName:  platform-gateway
 * @package:      com.platform.gateway.common.aspect
 * @className:    RateLimitAspect.java
 * @description:  限流切面
 * @author:       OprCalf
 * @date:         2019年5月22日
 */
@Component
@Aspect
@Slf4j
public class RateLimitAspect {

    // 用来存放不同接口的RateLimiter(key为接口名称，value为RateLimiter)
    private ConcurrentHashMap<String, RateLimiter> map = new ConcurrentHashMap<>();

    private RateLimiter rateLimiter;

    @Autowired
    private HttpServletResponse resp;

    @Autowired
    private HttpServletRequest req;

    @Pointcut("@annotation(com.platform.gateway.common.annotation.RateLimit)")
    public void serviceLimit() {
    }

    @Around("serviceLimit()")
    public Object around(ProceedingJoinPoint joinPoint) throws NoSuchMethodException {
        Object obj = null;
        // 获取拦截的方法名
        final Signature sig = joinPoint.getSignature();
        // 获取拦截的方法名
        final MethodSignature msig = (MethodSignature) sig;
        // 返回被织入增加处理目标对象
        final Object target = joinPoint.getTarget();
        // 为了获取注解信息
        final Method currentMethod = target.getClass().getMethod(msig.getName(), msig.getParameterTypes());
        // 获取注解信息
        final RateLimit annotation = currentMethod.getAnnotation(RateLimit.class);
        // 获取注解每秒加入桶中的token
        final int limitNum = annotation.limitNum();
        // 注解所在方法名区分不同的限流策略
        final String functionName = msig.getName();
        // 获取rateLimiter
        if (map.containsKey(functionName)) {
            rateLimiter = map.get(functionName);
        } else {
            map.put(functionName, RateLimiter.create(limitNum));
            rateLimiter = map.get(functionName);
        }
        try {
            if (rateLimiter.tryAcquire()) {
                // 执行方法
                obj = joinPoint.proceed();
            } else {
                // 拒绝了请求（服务降级）
                log.info("拒绝了请求：" + req.getRequestURI());
                resp.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
                resp.setContentType("application/json;charset=UTF-8");
                resp.getOutputStream()
                .write(MsgUtils.buildFailureMsg("请求繁忙,请稍后再试...").toString().getBytes("utf-8"));
            }
        }
        catch (final Throwable throwable) {
            resp.setStatus(HttpServletResponse.SC_BAD_REQUEST);
            resp.setContentType("application/json;charset=UTF-8");
            try {
                resp.getOutputStream()
                .write(MsgUtils.buildFailureMsg(throwable.getLocalizedMessage()).toString().getBytes("utf-8"));
            }
            catch (final Exception e) {
                e.printStackTrace();
            }
        }
        return obj;
    }

}
